//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <eltypes.h>
#include <_pubcrt.h>
#include "convertstr.h"
#include "_pubcrt.h"

#ifdef  __cplusplus
extern "C" {
#endif

_ELASTOS_NAMESPACE_USING

extern const char *icuEncoding[];

PCarQuintet __cdecl _WStringBuf_Init(PVoid pv, Int32 length, Boolean bHeapAlloced)
{
    if (length < 0) return NULL;

    PCarQuintet pCq = (PCarQuintet)pv;

    if (pCq) {
        Int32 size = (length + 1) * sizeof(WChar);
        CarQuintetFlags flags = CarQuintetFlag_Type_WChar;
        if (bHeapAlloced) flags |= CarQuintetFlag_HeapAlloced;
        _CarQuintet_Init(pCq, pCq + 1, size, sizeof(WChar), flags);
#ifndef _RELEASE
        memset(pCq->m_pBuf, 0xCC, size);
#endif
        *(WChar *)(pCq->m_pBuf) = L'\0';
    }

    return pCq;
}

PCarQuintet __cdecl _AStringBuf_Init(PVoid pv, Int32 length, Boolean bHeapAlloced)
{
    if (length < 0) return NULL;

    PCarQuintet pCq = (PCarQuintet)pv;

    if (pCq) {
        Int32 size = (length + 1) * sizeof(AChar);
        CarQuintetFlags flags = CarQuintetFlag_Type_AChar;
        if (bHeapAlloced) flags = CarQuintetFlag_HeapAlloced;
        _CarQuintet_Init(pCq, pCq + 1, size, sizeof(AChar), flags);
#ifndef _RELEASE
        memset(pCq->m_pBuf, 0xCC, size);
#endif
        *(AChar *)(pCq->m_pBuf) = '\0';
    }

    return pCq;
}

PCarQuintet __cdecl _WStringBuf_Alloc(Int32 length)
{
    if (length < 0) return NULL;

    Int32 size = (length + 1) * sizeof(WChar);
    PVoid pv = malloc(sizeof(CarQuintet) + size);
    return _WStringBuf_Init(pv, length, TRUE);
}

PCarQuintet __cdecl _AStringBuf_Alloc(Int32 length)
{
    if (length < 0) return NULL;

    Int32 size = (length + 1) * sizeof(AChar);
    PVoid pv = malloc(sizeof(CarQuintet) + size);
    return _AStringBuf_Init(pv, length, TRUE);
}

PCarQuintet __cdecl _WStringBuf_Alloc_Box(wchar_t *pwstr, Int32 size)
{
    if (!pwstr || size < 0) return NULL;

    PCarQuintet pCq = (PCarQuintet)malloc(sizeof(CarQuintet));

    if (pCq) {
        _WStringBuf_Box_Init(pCq, pwstr, size, TRUE);
    }

    return pCq;
}

PCarQuintet __cdecl _AStringBuf_Alloc_Box(char *pstr, Int32 size)
{
    if (!pstr || size < 0) return NULL;

    PCarQuintet pCq = (PCarQuintet)malloc(sizeof(CarQuintet));

    if (pCq) {
        _AStringBuf_Box_Init(pCq, pstr, size, TRUE);
    }

    return pCq;
}

Int32 __cdecl _WStringBuf_Insert(PCarQuintet pCq, Int32 offset, WString ws)
{
    if (!pCq || !pCq->m_pBuf || ws.IsNull()) return -1;

    Int32 nLen = pCq->m_used - sizeof(WChar);  //original string length
    Int32 nCap = pCq->m_size - sizeof(WChar);
    offset *= sizeof(WChar);

    if ((offset < 0) || (offset > nLen) || ws.IsNull()) {
        return -1;
    }

    Int32 nInsert = wcslen(ws) * sizeof(WChar);

    Int32 nRet = _BufferOf_Insert(pCq, offset, (Byte *)(const wchar_t *)ws, nInsert);

    if (pCq->m_used == pCq->m_size) {
        *(WChar *)((Byte *)pCq->m_pBuf + nCap) = L'\0';
        if (offset + nRet > nCap) nRet -= sizeof(WChar);
    }

    return nRet / sizeof(WChar);
}

Int32 __cdecl _AStringBuf_Insert(PCarQuintet pCq, Int32 offset, AString as)
{
    if (!pCq || !pCq->m_pBuf || as.IsNull()) return -1;

    Int32 nLen = pCq->m_used - sizeof(AChar);  //original string length
    Int32 nCap = pCq->m_size - sizeof(AChar);
    offset *= sizeof(AChar);

    if ((offset < 0) || (offset > nLen) || as.IsNull()) {
        return -1;
    }

    Int32 nInsert = strlen(as) * sizeof(AChar);

    Int32 nRet = _BufferOf_Insert(pCq, offset, (Byte *)(const char *)as, nInsert);

    if (pCq->m_used == pCq->m_size) {
        *(AChar *)((Byte *)pCq->m_pBuf + nCap) = '\0';
        if (offset + nRet > nCap) nRet -= sizeof(AChar);
    }

    return nRet / sizeof(AChar);
}

Int32 __cdecl _WStringBuf_Copy(PCarQuintet pCq, WString ws)
{
    if (!pCq || !pCq->m_pBuf || ws.IsNull()) return -1;

    Int32 nLen = (wcslen(ws) + 1) * sizeof(WChar);
    Int32 nCap = pCq->m_size - sizeof(WChar);

    Int32 nRet =  _BufferOf_CopyEx(pCq, (Byte *)(const wchar_t *)ws, nLen);

    if (nRet > nCap) {
        *(WChar *)((Byte *)pCq->m_pBuf + nCap) = L'\0';
        return nCap / sizeof(WChar);
    }

    return nRet / sizeof(WChar) - 1;
}

Int32 __cdecl _AStringBuf_Copy(PCarQuintet pCq, AString as)
{
    if (!pCq || !pCq->m_pBuf || as.IsNull()) return -1;

    Int32 nLen = (strlen(as) + 1) * sizeof(AChar);
    Int32 nCap = pCq->m_size - sizeof(AChar);

    Int32 nRet =  _BufferOf_CopyEx(pCq, (Byte *)(const char *)as, nLen);

    if (nRet > nCap) {
        *(AChar *)((Byte *)pCq->m_pBuf + nCap) = '\0';
        return nCap / sizeof(AChar);
    }

    return nRet / sizeof(AChar) - 1;
}

Int32 __cdecl _WStringBuf_Append_WString(PCarQuintet pCq, WString ws,
    Int32 offset, Int32 count)
{
    if (!pCq || !pCq->m_pBuf || ws.IsNull() || offset < 0 || count < 0) {
        return -1;
    }

    Int32 nLen = pCq->m_used - sizeof(WChar);  //original string length
    Int32 nCap = pCq->m_size - sizeof(WChar);

    Int32 len = 0;
    for(; len < offset + count; len++) {
        if (ws[len] == L'\0') break;
    }
    if (offset >= len) return -1;

    count = MIN(count, len - offset);

    offset *= sizeof(WChar);
    count *= sizeof(WChar);
    Int32 nRet = _BufferOf_Insert(pCq, nLen, (Byte *)(const wchar_t *)ws + offset,
        count);
    if (nRet == -1) {
        return -1;
    }
    if ((count + nLen > nCap) || (nRet < count)) {
        *(WChar *)((Byte *)pCq->m_pBuf + nCap) = L'\0';
        nRet -= sizeof(WChar);
    }

    return nRet / sizeof(WChar);
}

Int32 __cdecl _AStringBuf_Append_AString(PCarQuintet pCq, AString as,
    Int32 offset, Int32 count)
{
    if (!pCq || !pCq->m_pBuf || as.IsNull() || offset < 0 || count < 0) {
        return -1;
    }

    Int32 nLen = pCq->m_used - sizeof(AChar);  //original string length
    Int32 nCap = pCq->m_size - sizeof(AChar);

    Int32 len = 0;
    for(; len < offset + count; len++) {
        if (as[len] == '\0') break;
    }
    if (offset >= len) return -1;

    count = MIN(count, len - offset);

    offset *= sizeof(AChar);
    count *= sizeof(AChar);
    Int32 nRet = _BufferOf_Insert(pCq, nLen, (Byte *)(const char *)as + offset,
        count);
    if (nRet == -1) {
        return -1;
    }
    if ((count + nLen > nCap) || (nRet < count)) {
        *(AChar *)((Byte *)pCq->m_pBuf + nCap) = '\0';
        nRet -= sizeof(AChar);
    }

    return nRet / sizeof(AChar);
}

Int32 __cdecl _WStringBuf_Append_AChar(PCarQuintet pCq, AChar ac)
{
    return _WStringBuf_Append_WChar(pCq, ac);
}

Int32 __cdecl _WStringBuf_Append_WChar(PCarQuintet pCq, WChar wc)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    if (wc == L'\0') return 0;

    if (pCq->m_used > (Int32)(pCq->m_size - sizeof(WChar))) {
        return -1;
    }

    *(WChar *)((Byte *)pCq->m_pBuf + (pCq->m_used - sizeof(WChar))) = wc;
    *(WChar *)((Byte *)pCq->m_pBuf + pCq->m_used) =  L'\0';
    pCq->m_used += sizeof(WChar);

    return 1;
}

Int32 __cdecl _AStringBuf_Append_WChar(PCarQuintet pCq, WChar wc,
    Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    WStringBuf_<1> wsb;
    wsb.Append(wc);

    return _AStringBuf_Append_WString(pCq, wsb, 1, encoding);
}

Int32 __cdecl _AStringBuf_Append_AChar(PCarQuintet pCq, AChar ch)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    if (ch == '\0') return 0;

    if (pCq->m_used > (Int32)(pCq->m_size - sizeof(AChar))) {
        return -1;
    }

    *(AChar *)((Byte *)pCq->m_pBuf + (pCq->m_used - sizeof(AChar))) = ch;
    *(AChar *)((Byte *)pCq->m_pBuf + pCq->m_used) =  '\0';
    pCq->m_used += sizeof(AChar);

    return 1;
}

#define SetNumberInfo(number, mask) \
    {numberInfo.pCq = pCq; \
     numberInfo.value.number = value; \
     numberInfo.type = mask; \
     numberInfo.fmt = fmt;}

Int32 __cdecl _WStringBuf_Append_Int8(PCarQuintet pCq, Int8 value, Flags32 fmt)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    NumberInfo numberInfo;
    SetNumberInfo(n, NumberFormat_IntegerMask);

    return ConvertNumber(&numberInfo, 8);
}

Int32 __cdecl _AStringBuf_Append_Int8(PCarQuintet pCq, Int8 value, Flags32 fmt)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    NumberInfo numberInfo;
    SetNumberInfo(n, NumberFormat_IntegerMask);

    return ConvertNumber(&numberInfo, 8);
}

Int32 __cdecl _WStringBuf_Append_Int16(PCarQuintet pCq, Int16 value,
    Flags32 fmt)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    NumberInfo numberInfo;
    SetNumberInfo(n, NumberFormat_IntegerMask);

    return ConvertNumber(&numberInfo, 16);
}

Int32 __cdecl _AStringBuf_Append_Int16(PCarQuintet pCq, Int16 value,
    Flags32 fmt)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    NumberInfo numberInfo;
    SetNumberInfo(n, NumberFormat_IntegerMask);

    return ConvertNumber(&numberInfo, 16);
}

Int32 __cdecl _WStringBuf_Append_Int32(PCarQuintet pCq, Int32 value,
    Flags32 fmt)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    NumberInfo numberInfo;
    SetNumberInfo(n, NumberFormat_IntegerMask);

    return ConvertNumber(&numberInfo, 32);
}

Int32 __cdecl _AStringBuf_Append_Int32(PCarQuintet pCq, Int32 value,
    Flags32 fmt)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    NumberInfo numberInfo;
    SetNumberInfo(n, NumberFormat_IntegerMask);

    return ConvertNumber(&numberInfo, 32);
}

Int32 __cdecl _WStringBuf_Append_Int64(PCarQuintet pCq, Int64 value,
    Flags32 fmt)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    NumberInfo numberInfo;
    SetNumberInfo(n, NumberFormat_IntegerMask);

    return ConvertNumber(&numberInfo, 64);
}

Int32 __cdecl _AStringBuf_Append_Int64(PCarQuintet pCq, Int64 value,
    Flags32 fmt)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    NumberInfo numberInfo;
    SetNumberInfo(n, NumberFormat_IntegerMask);

    return ConvertNumber(&numberInfo, 64);
}

Int32 __cdecl _WStringBuf_Append_Double(PCarQuintet pCq, Double value,
    Flags32 fmt)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    NumberInfo numberInfo;
    SetNumberInfo(d, NumberFormat_DoubleMask);

    return ConvertNumber(&numberInfo);
}

Int32 __cdecl _AStringBuf_Append_Double(PCarQuintet pCq, Double value,
    Flags32 fmt)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    NumberInfo numberInfo;
    SetNumberInfo(d, NumberFormat_DoubleMask);

    return ConvertNumber(&numberInfo);
}

Int32 __cdecl _WStringBuf_Replace(PCarQuintet pCq, Int32 offset,
    Int32 count, WString ws)
{
    if (!pCq || !pCq->m_pBuf || ws.IsNull() || count < 0 || offset < 0 || offset >= pCq->m_used)
        return -1;

    Int32 nLen = _WString_GetLength(ws, count);
    if (nLen == -1) nLen = count;

    nLen *=  sizeof(WChar);
    Int32 used = pCq->m_used;

    offset *= sizeof(WChar);

    Int32 nRet = _BufferOf_Replace(pCq, offset, (PByte)(const wchar_t *)ws, nLen);
    wchar_t *pBuf = (wchar_t *)pCq->m_pBuf + pCq->m_used / sizeof(WChar);
    nRet = nRet / sizeof(WChar);

    if (used < pCq->m_used
            || (*pBuf != L'\0'
            && pCq->m_used == pCq->m_size)) {
        if (pCq->m_used < pCq->m_size)
            pCq->m_used += sizeof(WChar);
        else {
            nRet--;
            pBuf--;
        }

        *pBuf = L'\0';
    }
    return nRet;
}

Int32 __cdecl _AStringBuf_Replace(PCarQuintet pCq, Int32 offset,
    Int32 count, AString as)
{
    if (!pCq || !pCq->m_pBuf || as.IsNull() || count < 0 || offset < 0 || offset >= pCq->m_used)
        return -1;

    Int32 nLen = _AString_GetLength(as, count);
    if (nLen == -1) nLen = count;
    Int32 used = pCq->m_used;

    offset *= sizeof(AChar);


    Int32 nRet = _BufferOf_Replace(pCq, offset, (PByte)(const char *)as, nLen);
    char *pBuf = (char *)pCq->m_pBuf + pCq->m_used;
    nRet = nRet / sizeof(AChar);

    if (used < pCq->m_used
            || (*pBuf != '\0'
            && pCq->m_used == pCq->m_size)) {
        if (pCq->m_used < pCq->m_size)
            pCq->m_used++;
        else {
            nRet--;
            pBuf--;
        }

        *pBuf = '\0';
    }
    return nRet;
}

PCarQuintet  __cdecl _WStringBuf_Box_Init(PCarQuintet pCq, wchar_t *wstr, Int32 size,
    Boolean bHeapAlloced)
{
    if (!pCq) return NULL;

    Int32 used = 0;
    if (wstr) {
        if (size) {
            used = _WString_GetLength(wstr, size);
            if (used == -1 || used == size) { //length >= size
                wstr[size - 1] = L'\0';
                used = size;
            }
            else {
                used++;
            }
        }
        else {
            wstr[0] = L'\0';
            used = 0;
        }
    }
    else {
        size = 0;
    }

    CarQuintetFlags flags = CarQuintetFlag_Type_WChar;
    if (bHeapAlloced) flags |= CarQuintetFlag_HeapAlloced;
    return _CarQuintet_Init(pCq, wstr, size * sizeof(WChar), used * sizeof(WChar), flags);
}

PCarQuintet  __cdecl _AStringBuf_Box_Init(PCarQuintet pCq, char *str, Int32 size,
    Boolean bHeapAlloced)
{
    if (!pCq) return NULL;

    Int32 used = 0;
    if (str) {
        if (size) {
            used = _AString_GetLength(str, size);
            if (used == -1 || used == size) { //length >= size
                str[size - 1] = '\0';
                used = size;
            }
            else {
                used++;
            }
        }
        else {
            str[0] = '\0';
            used = 0;
        }
    }
    else {
        size = 0;
    }

    CarQuintetFlags flags = CarQuintetFlag_Type_AChar;
    if (bHeapAlloced) flags |= CarQuintetFlag_HeapAlloced;
    return _CarQuintet_Init(pCq, str, size * sizeof(AChar), used * sizeof(AChar), flags);
}

Char32 _getAStringCharAt(const char *encoding, const char *str, Int32 index);
Char32 _getWStringCharAt(const wchar_t *str, Int32 index);
Int32 _getAStringLength(const char *encoding, const char *str);
Int32 _getWStringLength(const wchar_t *str);

Int32 __cdecl _WStringBuf_Append_AString(PCarQuintet pCq, AString as, Int32 len,
    Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf || as.IsNull()) return -1;

    wchar_t *pws = (wchar_t *)((PByte)pCq->m_pBuf + pCq->m_used - sizeof(WChar));
    Int32 n = (pCq->m_size - pCq->m_used) / sizeof(WChar);
    if (len == -1) len = strlen(as);

    _toWString(icuEncoding[encoding], pws, &n, as, &len);

    pCq->m_used += n * sizeof(WChar);

    *(wchar_t *)((PByte)pCq->m_pBuf + pCq->m_used - sizeof(WChar)) = L'\0';

    return len;
}

Int32 __cdecl _AStringBuf_Append_WString(PCarQuintet pCq, WString ws, Int32 len,
    Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf || ws.IsNull()) return -1;

    char *pstr = (char *)((PByte)pCq->m_pBuf + pCq->m_used - sizeof(AChar));
    Int32 n = (pCq->m_size - pCq->m_used) / sizeof(AChar);
    if (len == -1) len = wcslen(ws);

    _fromWString(icuEncoding[encoding], pstr, &n, ws, &len);

    pCq->m_used += n * sizeof(AChar);

    *(char *)((PByte)pCq->m_pBuf + pCq->m_used - sizeof(AChar)) = '\0';

    return len;
}

Int32 __cdecl _WStringBuf_SetLength(PCarQuintet pCq, Int32 len)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    Int32 cap = pCq->m_size / sizeof(WChar) - 1;
    Int32 oldlen = _WString_GetLength((wchar_t *)pCq->m_pBuf, cap);

    if (len < 0) return oldlen;
    if (oldlen != -1) {
        if (oldlen < len) len = oldlen;
    }
    else {
        if (cap < len) len = cap;
    }

    *((wchar_t *)pCq->m_pBuf + len) = L'\0';
    pCq->m_used = (len + 1) * sizeof(WChar);
    return len;
}

Int32 __cdecl _AStringBuf_SetLength(PCarQuintet pCq, Int32 len)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    Int32 cap = pCq->m_size / sizeof(AChar) - 1;
    Int32 oldlen = _AString_GetLength((char *)pCq->m_pBuf, cap);

    if (len < 0) return oldlen;
    if (oldlen != -1) {
        if (oldlen < len) len = oldlen;
    }
    else {
        if (cap < len) len = cap;
    }

    *((char *)pCq->m_pBuf + len) = '\0';
    pCq->m_used = (len + 1) * sizeof(AChar);
    return len;
}

//---------
Int32 __cdecl _WStringBuf_ToInt32(const PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return 0;
    return _WString_ToInt32((const wchar_t*)pCq->m_pBuf);
}

Int32 __cdecl _AStringBuf_ToInt32(const PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return 0;
    return _AString_ToInt32((const char*)pCq->m_pBuf);
}

Int64 __cdecl _WStringBuf_ToInt64(const PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return 0;
    return _WString_ToInt64((const wchar_t*)pCq->m_pBuf);
}

Int64 __cdecl _AStringBuf_ToInt64(const PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return 0;
    return _AString_ToInt64((const char*)pCq->m_pBuf);
}

Boolean __cdecl _WStringBuf_ToBoolean(const PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return FALSE;
    return _WString_ToBoolean((const wchar_t*)pCq->m_pBuf);
}

Boolean __cdecl _AStringBuf_ToBoolean(const PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return FALSE;
    return _AString_ToBoolean((const char*)pCq->m_pBuf);
}

Double __cdecl _WStringBuf_ToDouble(const PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return 0.0;
    return _WString_ToDouble((const wchar_t*)pCq->m_pBuf);
}

Double __cdecl _AStringBuf_ToDouble(const PCarQuintet pCq)
{
    assert(pCq && pCq->m_pBuf);
    if (!pCq || !pCq->m_pBuf) return 0.0;
    return _AString_ToDouble((const char*)pCq->m_pBuf);
}

//---------
Int32 __cdecl _WStringBuf_GetCharCount(const PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _getWStringLength((wchar_t *)pCq->m_pBuf);
}

Int32 __cdecl _AStringBuf_GetCharCount(const PCarQuintet pCq, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _getAStringLength(icuEncoding[encoding], (char *)pCq->m_pBuf);
}

Char32 __cdecl _WStringBuf_GetChar(const PCarQuintet pCq, Int32 index)
{
    if (!pCq || !pCq->m_pBuf) return 0xFFFFFFFF;
    if ((index < 0) || (index >= (Int32)(pCq->m_used / sizeof(WChar)))) {
        return 0xFFFFFFFF;
    }

    return _getWStringCharAt((wchar_t *)pCq->m_pBuf, index);
}

Char32 __cdecl _AStringBuf_GetChar(const PCarQuintet pCq, Int32 index,
    Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return 0xFFFFFFFF;
    if ((index < 0) || (index >= (Int32)(pCq->m_used / sizeof(AChar)))) {
        return 0xFFFFFFFF;
    }

    return _getAStringCharAt(icuEncoding[encoding], (char *)pCq->m_pBuf, index);
}

//---- Contains ----
Boolean __cdecl _AStringBuf_Contains(const PCarQuintet pCq, const char *substr,
    StringCase stringCase, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return FALSE;
    return _AString_Contains((const char*)pCq->m_pBuf, substr, stringCase, encoding);
}

Boolean __cdecl _WStringBuf_Contains(const PCarQuintet pCq, const wchar_t *substr,
    StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return FALSE;
    return _WString_Contains((const wchar_t*)pCq->m_pBuf, substr, stringCase);
}

//---- StartWith ----
Boolean __cdecl _AStringBuf_StartWith(const PCarQuintet pCq, const char *substr,
    StringCase stringCase, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return FALSE;
    return _AString_StartWith((const char*)pCq->m_pBuf, substr, stringCase, encoding);
}

Boolean __cdecl _WStringBuf_StartWith(const PCarQuintet pCq,
    const wchar_t *substr, StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return FALSE;
    return _WString_StartWith((const wchar_t*)pCq->m_pBuf, substr, stringCase);
}

//---- EndWith ----
Boolean __cdecl _AStringBuf_EndWith(const PCarQuintet pCq, const char *substr,
    StringCase stringCase, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return FALSE;
    return _AString_EndWith((const char*)pCq->m_pBuf, substr, stringCase, encoding);
}

Boolean __cdecl _WStringBuf_EndWith(const PCarQuintet pCq,
    const wchar_t *substr, StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return FALSE;
    return _WString_EndWith((const wchar_t*)pCq->m_pBuf, substr, stringCase);
}

//---- IndexOf ----
Int32 __cdecl _AStringBuf_IndexOf_AChar(const PCarQuintet pCq, char ch,
    StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _AString_IndexOf_AChar((const char*)pCq->m_pBuf, ch, stringCase);
}

Int32 __cdecl _AStringBuf_IndexOf_AnyAChar(const PCarQuintet pCq,
    const char* strCharSet, StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _AString_IndexOf_AnyAChar((const char*)pCq->m_pBuf, strCharSet, stringCase);
}

Int32 __cdecl _AStringBuf_IndexOf_Char(const PCarQuintet pCq,
    Char32 ch, StringCase stringCase, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _AString_IndexOf_Char((const char*)pCq->m_pBuf, ch, stringCase, encoding);
}

Int32 __cdecl _AStringBuf_IndexOf_AnyChar(const PCarQuintet pCq,
    Char32 *strCharSet, StringCase stringCase, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _AString_IndexOf_AnyChar((const char*)pCq->m_pBuf, strCharSet,
        stringCase, encoding);
}

Int32 __cdecl _AStringBuf_IndexOf_Substring(const PCarQuintet pCq,
    const char *substr, StringCase stringCase, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _AString_IndexOf_Substring((const char*)pCq->m_pBuf, substr, stringCase, encoding);
}

Int32 __cdecl _WStringBuf_IndexOf_WChar(const PCarQuintet pCq, wchar_t ch,
    StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _WString_IndexOf_WChar((const wchar_t*)pCq->m_pBuf, ch, stringCase);
}

Int32 __cdecl _WStringBuf_IndexOf_AnyWChar(const PCarQuintet pCq,
    const wchar_t* strCharSet, StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _WString_IndexOf_AnyWChar((const wchar_t*)pCq->m_pBuf, strCharSet, stringCase);
}

Int32 __cdecl _WStringBuf_IndexOf_Char(const PCarQuintet pCq, Char32 ch,
    StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _WString_IndexOf_Char((const wchar_t*)pCq->m_pBuf, ch, stringCase);
}

Int32 __cdecl _WStringBuf_IndexOf_AnyChar(const PCarQuintet pCq,
    Char32 *strCharSet, StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _WString_IndexOf_AnyChar((const wchar_t*)pCq->m_pBuf, strCharSet, stringCase);
}

Int32 __cdecl _WStringBuf_IndexOf_Substring(const PCarQuintet pCq,
    const wchar_t *substr, StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _WString_IndexOf_Substring((const wchar_t*)pCq->m_pBuf, substr, stringCase);
}

//---- LastIndexOf ----
Int32 __cdecl _AStringBuf_LastIndexOf_AChar(const PCarQuintet pCq, char ch,
    StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _AString_LastIndexOf_AChar((const char*)pCq->m_pBuf, ch, stringCase);
}

Int32 __cdecl _AStringBuf_LastIndexOf_AnyAChar(const PCarQuintet pCq,
    const char* strCharSet, StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _AString_LastIndexOf_AnyAChar((const char*)pCq->m_pBuf, strCharSet, stringCase);
}

Int32 __cdecl _AStringBuf_LastIndexOf_Char(const PCarQuintet pCq, Char32 ch,
    StringCase stringCase, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _AString_LastIndexOf_Char((const char*)pCq->m_pBuf, ch, stringCase, encoding);
}

Int32 __cdecl _AStringBuf_LastIndexOf_AnyChar(const PCarQuintet pCq,
    Char32 *strCharSet, StringCase stringCase, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _AString_LastIndexOf_AnyChar((const char*)pCq->m_pBuf, strCharSet,
        stringCase, encoding);
}

Int32 __cdecl _AStringBuf_LastIndexOf_Substring(const PCarQuintet pCq,
    const char *substr, StringCase stringCase, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _AString_LastIndexOf_Substring((const char*)pCq->m_pBuf, substr,
        stringCase, encoding);
}

Int32 __cdecl _WStringBuf_LastIndexOf_WChar(const PCarQuintet pCq,
    wchar_t ch, StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _WString_LastIndexOf_WChar((const wchar_t*)pCq->m_pBuf, ch, stringCase);
}

Int32 __cdecl _WStringBuf_LastIndexOf_AnyWChar(const PCarQuintet pCq,
    const wchar_t *strCharSet, StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _WString_LastIndexOf_AnyWChar((const wchar_t*)pCq->m_pBuf,
        strCharSet, stringCase);
}

Int32 __cdecl _WStringBuf_LastIndexOf_Char(const PCarQuintet pCq, Char32 ch,
     StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _WString_LastIndexOf_Char((const wchar_t*)pCq->m_pBuf, ch, stringCase);
}

Int32 __cdecl _WStringBuf_LastIndexOf_AnyChar(const PCarQuintet pCq,
    Char32 *strCharSet, StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _WString_LastIndexOf_AnyChar((const wchar_t*)pCq->m_pBuf, strCharSet, stringCase);
}

Int32 __cdecl _WStringBuf_LastIndexOf_Substring(const PCarQuintet pCq,
    const wchar_t *substr, StringCase stringCase)
{
    if (!pCq || !pCq->m_pBuf) return -1;
    return _WString_LastIndexOf_Substring((const wchar_t*)pCq->m_pBuf, substr, stringCase);
}

//---- Substring ----
char* __cdecl _AStringBuf_Substring(const PCarQuintet pCq, Int32 start, PCarQuintet sub,
    Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf || !sub || !sub->m_pBuf) return NULL;
    return _AString_Substring_Buffer((const char*)pCq->m_pBuf, start, sub, encoding);
}

char* __cdecl _AStringBuf_Substring_Length(const PCarQuintet pCq,
    Int32 start, Int32 len, PCarQuintet sub, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf || !sub || !sub->m_pBuf) return NULL;
    return _AString_Substring_Length_Buffer((const char*)pCq->m_pBuf, start, len,
        sub, encoding);
}

wchar_t* __cdecl _WStringBuf_Substring(const PCarQuintet pCq, Int32 start, PCarQuintet sub)
{
    if (!pCq || !pCq->m_pBuf || !sub || !sub->m_pBuf) return NULL;
    return _WString_Substring_Buffer((const wchar_t*)pCq->m_pBuf, start, sub);
}

wchar_t* __cdecl _WStringBuf_Substring_Length(const PCarQuintet pCq,
    Int32 start, Int32 len, PCarQuintet sub)
{
    if (!pCq || !pCq->m_pBuf || !sub || !sub->m_pBuf) return NULL;
    return _WString_Substring_Length_Buffer((const wchar_t*)pCq->m_pBuf, start, len, sub);
}

//---- ToLowerCase ----
PCarQuintet __cdecl _AStringBuf_ToLowerCase(PCarQuintet pCq, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return NULL;
    _AString_ToLowerCase((const char*)pCq->m_pBuf, pCq, encoding);
    return pCq;
}

PCarQuintet __cdecl _WStringBuf_ToLowerCase(PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return NULL;
    _WString_ToLowerCase((const wchar_t*)pCq->m_pBuf, pCq);
    return pCq;
}

//---- ToUpperCase ----
PCarQuintet __cdecl _AStringBuf_ToUpperCase(PCarQuintet pCq,
    Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return NULL;
    _AString_ToUpperCase((const char*)pCq->m_pBuf, pCq, encoding);
    return pCq;
}

PCarQuintet __cdecl _WStringBuf_ToUpperCase(PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return NULL;
    _WString_ToUpperCase((const wchar_t*)pCq->m_pBuf, pCq);
    return pCq;
}

//---- TrimStart ----
PCarQuintet __cdecl _AStringBuf_TrimStart(PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return NULL;
    _AString_TrimStart((const char*)pCq->m_pBuf, pCq);
    return pCq;
}

PCarQuintet __cdecl _WStringBuf_TrimStart(PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return NULL;
    _WString_TrimStart((const wchar_t*)pCq->m_pBuf, pCq);
    return pCq;
}

//---- TrimEnd ----
PCarQuintet __cdecl _AStringBuf_TrimEnd(PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return NULL;
    _AString_TrimEnd((const char*)pCq->m_pBuf, pCq);
    return pCq;
}

PCarQuintet __cdecl _WStringBuf_TrimEnd(PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return NULL;
    _WString_TrimEnd((const wchar_t*)pCq->m_pBuf, pCq);
    return pCq;
}

//---- Trim ----
PCarQuintet __cdecl _AStringBuf_Trim(PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return NULL;
    _AString_Trim((const char*)pCq->m_pBuf, pCq);
    return pCq;
}

PCarQuintet __cdecl _WStringBuf_Trim(PCarQuintet pCq)
{
    if (!pCq || !pCq->m_pBuf) return NULL;
    _WString_Trim((const wchar_t*)pCq->m_pBuf, pCq);
    return pCq;
}


//---- PadLeft ----
PCarQuintet __cdecl _AStringBuf_PadLeft(PCarQuintet pCq, Int32 width)
{
    return _AStringBuf_PadLeft_AChar(pCq, width, ' ');
}

PCarQuintet __cdecl _WStringBuf_PadLeft(PCarQuintet pCq, Int32 width)
{
    return _WStringBuf_PadLeft_WChar(pCq, width, L' ');
}

PCarQuintet __cdecl _AStringBuf_PadLeft_AChar(PCarQuintet pCq, Int32 width,
        AChar ch)
{
    if (!pCq || !pCq->m_pBuf || width < 0) return NULL;
    Int32 len = pCq->m_used - 1;
    if (width <= len) return NULL;

    width = MIN(width, pCq->m_size - 1);
    Int32 move = width - len;
    memmove((char *)pCq->m_pBuf + move, pCq->m_pBuf, len);
    memset(pCq->m_pBuf, ch, move);

    *((char *)pCq->m_pBuf + width) = '\0';
    pCq->m_used = width + sizeof(AChar);
    return pCq;
}

PCarQuintet __cdecl _WStringBuf_PadLeft_WChar(PCarQuintet pCq, Int32 width,
        WChar ch)
{
    if (!pCq || !pCq->m_pBuf || width < 0) return NULL;
    Int32 len = (pCq->m_used -1) / sizeof(WChar);
    if (width <= len) return NULL;

    width = MIN(width, (Int32)(pCq->m_size / sizeof(WChar)) - 1);
    Int32 move = width - len;
    memmove((Byte *)pCq->m_pBuf + move * sizeof(WChar),
            pCq->m_pBuf, len * sizeof(WChar));
    for (Int32 i = 0; i < move; i++) {
        *((wchar_t *)pCq->m_pBuf + i) = ch;
    }

    *((wchar_t *)pCq->m_pBuf + width) = '\0';
    pCq->m_used = (width + 1) * sizeof(WChar);
    return pCq;
}

//AStringBuf& AStringBuf::PadCharLeft(Int32 width, Char32 ch);
//
//WStringBuf& WStringBuf::PadCharLeft(Int32 width, Char32 ch);


//---- PadRight ----
PCarQuintet _AStringBuf_PadRight(PCarQuintet pCq, Int32 width)
{
    return _AStringBuf_PadRight_AChar(pCq, width, ' ');
}

PCarQuintet _WStringBuf_PadRight(PCarQuintet pCq, Int32 width)
{
    return _WStringBuf_PadRight_WChar(pCq, width, L' ');
}

PCarQuintet _AStringBuf_PadRight_AChar(PCarQuintet pCq, Int32 width, AChar ch)
{
    if (!pCq || !pCq->m_pBuf) return NULL;

    Int32 len = pCq->m_used - 1;
    if (width <= len) return NULL;

    width = MIN(width, pCq->m_size - 1);
    Int32 pad = width - len;
    memset((char *)pCq->m_pBuf + len, ch, pad);

    *((char *)pCq->m_pBuf + width) = '\0';
    pCq->m_used = width + sizeof(AChar);
    return pCq;
}

PCarQuintet _WStringBuf_PadRight_WChar(PCarQuintet pCq, Int32 width, WChar ch)
{
    if (!pCq || !pCq->m_pBuf) return NULL;
    Int32 len = (pCq->m_used - 1) / sizeof(WChar);
    if (width <= len) return NULL;

    width = MIN(width, (Int32)(pCq->m_size / sizeof(WChar)) - 1);
    Int32 pad = width - len;
    for (Int32 i = 0; i < pad; i++) {
        *((wchar_t *)pCq->m_pBuf + len + i) = ch;
    }

    *((wchar_t *)pCq->m_pBuf + width) = '\0';
    pCq->m_used = (width + 1) * sizeof(WChar);
    return pCq;
}

//AStringBuf& AStringBuf::PadCharRight(Int32 width, Char32 ch);
//
//WStringBuf& WStringBuf::PadCharRight(Int32 width, Char32 ch);

Int32 __cdecl _WStringBuf_EstimateAStringLength(const PCarQuintet pCq, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return -1;

    Int32 insize = pCq->m_used / sizeof(wchar_t);
    Int32 outsize = insize * 4;
    return _fromWString(icuEncoding[encoding], NULL, (Int32 *)&outsize,
                (wchar_t*)pCq->m_pBuf, (Int32 *)&insize);
}

Int32 __cdecl _AStringBuf_EstimateWStringLength(const PCarQuintet pCq, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf) return -1;

    Int32 insize = pCq->m_used;
    Int32 outsize = insize;
    return _toWString(icuEncoding[encoding], NULL, (Int32 *)&outsize,
                (char*)pCq->m_pBuf, (Int32 *)&insize);
}

#define U16_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)

#define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)

#define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)

#define U16_GET_SUPPLEMENTARY(lead, trail) \
    (((lead)<<10UL)+(trail)-U16_SURROGATE_OFFSET)

#define HexToChar(digit) \
    {if (digit < 10) ch = (char)('0' + digit); \
     else ch = (char)('a' - 10 + digit);}

PCarQuintet __cdecl _AStringBuf_EncodeURL(PCarQuintet pCq, WString ws, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf || ws.IsNull()) return NULL;
    AChar *str = (AChar *)pCq->m_pBuf;

    for (Int32 i = 0; i < ws.GetLength() && pCq->m_used < pCq->m_size; i++) {
        Int32 c = (Int32)ws[i];
        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
            (c >= '0' && c <= '9') || !!wcschr(L" -_.*", c)) {
            if (c == ' ') {
                c = '+';
            }
            *str++ = (AChar)c;
            pCq->m_used += sizeof(AChar);
        }
        else {
            // convert to external encoding before hex conversion
            AChar buf[10] = {0};    // rather arbitrary limit, but safe for now
            Int32 insize = 1;
            Int32 outsize = 10;

		    /*
		     * If this character represents the start of a Unicode
		     * surrogate pair, then pass in two characters. It's not
		     * clear what should be done if a bytes reserved in the
		     * surrogate pairs range occurs outside of a legal
		     * surrogate pair. For now, just treat it as if it were
		     * any other character.
		     */
            if (U16_IS_SURROGATE(c)) {
                if ((i + 1) < ws.GetLength()) {
                    Int32 d = (Int32)ws[i+1];
                    if (U16_IS_TRAIL(d)) {
                        c = U16_GET_SUPPLEMENTARY(c, d);
                        insize++;
                        i++;
                    }
                }
            }
            Int32 ret = _fromWString(icuEncoding[encoding], buf, &outsize,
                        (WChar *)&c, &insize);
            if (ret == -1) return NULL;

            if((pCq->m_used + ret * 3 * (Int32)sizeof(AChar)) > pCq->m_size) break;

            for (Int32 j = 0; j < (Int32)strlen(buf); j++) {
                *str++ = '%';
                char ch;
                HexToChar(((buf[j] >> 4) & 0xF));
                // converting to use uppercase letter as part of
		        // the hex value if ch is a letter.
                if (ch >= 'a' && ch <='z') {
                    ch -= ('a' - 'A');
                }
                *str++ = ch;
                HexToChar((buf[j] & 0xF));
                if (ch >= 'a' && ch <='z') {
                    ch -= ('a' - 'A');
                }
                *str++ = ch;
                pCq->m_used += 3 * sizeof(AChar);
            }
        }
    }

    *str = '\0';
    return pCq;
}

#define StrToHex(start, end) \
    {while(start < end) { \
         if ((*start >= '0') && (*start <= '9')) buf[pos] = (buf[pos] << 4) + *start - '0'; \
         else if ((*start >= 'a') && (*start <= 'f') ) buf[pos] = (buf[pos] << 4) + *start - 'a' + 10; \
         else if ((*start >= 'A') && (*start <= 'F') ) buf[pos] = (buf[pos] << 4) + *start - 'A' + 10; \
         else buf[pos] = '\0'; \
         start++;}}

PCarQuintet __cdecl _WStringBuf_DecodeURL(PCarQuintet pCq, AString as, Encoding encoding)
{
    if (!pCq || !pCq->m_pBuf || as.IsNull()) return NULL;

    Int32 numChars = as.GetLength();
    Int32 i = 0;
    WChar *wstr = (WChar *)pCq->m_pBuf;

    while (i < numChars && pCq->m_used < pCq->m_size) {
        AChar c = as[i];
        switch(c) {
            case '+':
                *wstr++ = L' ';
                i++;
                pCq->m_used += sizeof(WChar);
                break;
            case '%': {
                AChar *buf = (AChar *)malloc((numChars - i) / 3 + 1);
                if (!buf) return NULL;
                memset(buf, 0, (numChars - i) / 3 + 1);
                int pos = 0;

                while (((i + 2) < numChars) && (c == '%')) {
                    const char *start = (const char *)as + i + 1;
                    StrToHex(start, ((const char *)as + i + 3));
                    pos++;
                    i += 3;

                    if (i < numChars) c = as[i];
                }

                Int32 insize = strlen(buf);
                Int32 outsize = (pCq->m_size - pCq->m_used) / sizeof(WChar);
                Int32 ret = _toWString(icuEncoding[encoding], wstr, &outsize,
                                buf, &insize);
                if (ret == -1) return NULL;

                wstr += ret;
                pCq->m_used += ret * sizeof(WChar);
                free(buf);
                break;
            }
            default:
                *wstr++ = (wchar_t)c;
                i++;
                pCq->m_used += sizeof(WChar);
                break;
        }
    }

    *wstr = L'\0';
    return pCq;
}

#ifdef  __cplusplus
}
#endif
